/*!
巧妙运用broadcast，channel完成优雅关机问题

 - broadcast (Sender关闭，rx.recv将收到Closed)，所有线程监听此rx，收到信息则退出
 - channel(Sender关闭，rx.recv收到None)，所有线程都分配一个tx, 主线程监听rx, 如果所有工作线程都退出，则tx关闭，则主线程rx收到信息（None），表示完成收尾工作。

 当前案例分别启动了Deamon和Listener两个主服务，所以针对 notify_shutdown, shutdown_complete_tx 分别做了clone,
 因此，需要做2此显式的drop，才能正确的关闭这2中通信管道。drop(notify_shutdown); drop(shutdown_complete_tx);

 */

use crate::shutdown::Shutdown;
//use crate::*;
use crate::worker::*;
use crate::Cli;
use crate::*;
// use anyhow::anyhow;
// use log::Level::Info as INFO; // {Error as ERROR, Info as INFO};
use tokio::sync::{broadcast, mpsc};
use tracing::{error, event, info};

#[derive(Debug)]
struct Deamon {
    notify_shutdown: broadcast::Sender<()>,
    shutdown_complete_rx: mpsc::Receiver<()>,
    shutdown_complete_tx: mpsc::Sender<()>,
}

pub async fn startup(cli: Cli) -> Result<()> {
    let (notify_shutdown, _) = broadcast::channel(1);
    let (shutdown_complete_tx, shutdown_complete_rx) = mpsc::channel(1);

    let mut server = Deamon {
        notify_shutdown,
        shutdown_complete_tx,
        shutdown_complete_rx,
    };
    server.run(cli).await.unwrap();

    // 前面不能阻塞！
    info!("注意：看见这里，各线程才能安全退出！");
    tokio::select! {
        _ = shutdown_signal("main") => {
            error!("try to signal shutting down all servers now!");
        },
    }

    let Deamon {
        mut shutdown_complete_rx,
        shutdown_complete_tx,
        notify_shutdown,
        ..
    } = server;

    drop(notify_shutdown);
    drop(shutdown_complete_tx);

    /*
    这里注意，因为前面对2种管道进行了clone， 所以必须相应 drop

    shutdown_complete_tx 放入每个work线程中，作用就是表示完成收尾工作，安全退出了
    只要有一个shutdown_complete_tx引用存在，下面的recv就会阻塞，直到工作线程退出（释放给他的shutdown_complete_tx）
    */
    let _ = shutdown_complete_rx.recv().await;
    info!("各工作线程安全关闭！");
    Ok(())
}

impl Deamon {
    async fn run(&mut self, cli: Cli) -> crate::Result<()> {
       
    let cfg_file = &cli.config;    
    let cfg:Config = serde_json::from_str( String::from_utf8(std::fs::read(&cfg_file).unwrap()).unwrap().as_str() ).unwrap();  
    
    let dbpath = PathBuf::from(&cfg.site_root).join("db");
    if dbpath.exists() == false {
         std::fs::create_dir_all(dbpath).unwrap();
    }
    let database_name = format!("sqlite:{}{}db{}hello.db", cfg.site_root, std::path::MAIN_SEPARATOR, std::path::MAIN_SEPARATOR);
    let dbpool = db::create_db_pool(&database_name).await?;

    let shared = Shared::new(cfg_file, dbpool);
    let shared: Arc<Shared> = Arc::new( shared );

        // worker deamon
        // 执行真正的请求处理和应答反馈。
       
        let mut worker = Worker {
            shared: Arc::clone(&shared),
            // Receive shutdown notifications.
            shutdown: Shutdown::new(self.notify_shutdown.subscribe()),
            _shutdown_complete: self.shutdown_complete_tx.clone(),           
        };
        let _ = tokio::spawn(async move {
            if let Err(err) = worker.run().await {
                error!("{:?} {}", err, "start worker error");                
            }
        });

        //
        // web server
        // 启动web服务线程
        //
        let wshared = Arc::clone(&shared);
        let _ = tokio::spawn(async move {
            if let Err(err) = axum_main(&cfg, wshared ).await {
                 error!("{:#?}, {}", err, "axum server error");
            } else {
                // event!(target:"shutdown", loglevel(Error), "Web server is shutdown, OK");
            }
        });
        info!("finished Demaon runner, see here is ok!");
        Ok(())
    }
}
